package register

import (
	"encoding/base64"
	"encoding/binary"
	"fmt"
	"github.com/gogf/guuid"
	"math/rand"
	ecc2 "sieve_engine/execute/whatsapp/lib/libsignal/ecc"
	"sieve_engine/execute/whatsapp/lib/libsignal/keys/identity"
	"sieve_engine/execute/whatsapp/lib/libsignal/serialize"
	"sieve_engine/execute/whatsapp/lib/libsignal/state/record"
	"sieve_engine/execute/whatsapp/lib/libsignal/util/keyhelper"
	"strings"
	"time"
)

const WaConfigLogTag = "WAConfig"

type WAConfig struct {
	// 区号
	CC string
	// 手机号
	In string
	// guuid
	FDid string
	// 随机16位
	Exid string
	//
	MCC string
	// mnc
	MNC         string
	SimMcc      string
	SimMnc      string
	BackupToken string
	Id          string

	RegistrationId      uint32
	ClientStaticKeyPair *ecc2.ECKeyPair
	IdentityKeyPair     *identity.KeyPair
	SignedPreKey        *record.SignedPreKey
	//新加给值
	EIdent        string
	EIdentPrivate [32]byte
	EsKeyId       string
	EsKeyVal      string
	EsKeySig      string
	AuthKey       string
	StaticPubKey  string
	StaticPriKey  string
}

// SetRegistrationVal 注册给值
func (c *WAConfig) SetRegistrationVal() *WAConfig {
	//e_ident
	c.EIdent = base64.RawURLEncoding.EncodeToString(c.IdentityKeyPair.PublicKey().Serialize()[1:])
	c.EIdentPrivate = c.IdentityKeyPair.PrivateKey().Serialize()
	eSkeyId := make([]byte, 4)
	binary.BigEndian.PutUint32(eSkeyId, c.SignedPreKey.ID())
	c.EsKeyId = base64.RawURLEncoding.EncodeToString(eSkeyId[1:])
	c.EsKeyVal = base64.RawURLEncoding.EncodeToString(c.SignedPreKey.KeyPair().PublicKey().Serialize()[1:])
	eSkeySig := make([]byte, 64)
	signature := c.SignedPreKey.Signature()
	copy(eSkeySig[:], signature[:])
	c.EsKeySig = base64.RawURLEncoding.EncodeToString(eSkeySig)
	c.AuthKey = base64.RawURLEncoding.EncodeToString(c.ClientStaticKeyPair.PublicKey().Serialize()[1:])
	//add
	clientStaticpriKey := c.ClientStaticKeyPair.PrivateKey().Serialize()
	_clientStaticPriKey := make([]byte, len(clientStaticpriKey))
	copy(_clientStaticPriKey[:], clientStaticpriKey[:])
	cliStaticKeyPair := append(_clientStaticPriKey, c.ClientStaticKeyPair.PublicKey().Serialize()[1:]...)
	c.StaticPubKey = base64.StdEncoding.EncodeToString(cliStaticKeyPair[32:])
	c.StaticPriKey = base64.StdEncoding.EncodeToString(cliStaticKeyPair[:32])
	return c
}

func (c *WAConfig) GenConfigJson(edgeRouting string) interface{} {
	config := map[string]string{
		"status": "ok",
		"cc":     c.CC,
		//"client_static_keypair": base64.StdEncoding.EncodeToString(cliStaticKeyPair),
		"edge_routing_info": edgeRouting,
		//"expid": 			   	c.Exid,
		"phone_id": c.FDid,
		//"id":                    c.Id,
		"login":        c.In,
		"mcc":          c.MCC,
		"mnc":          c.MNC,
		"phone":        c.In,
		"pushname":     randSeq(7),
		"sim_mcc":      c.SimMcc,
		"sim_mnc":      c.SimMnc,
		"StaticPubKey": c.StaticPubKey,
		"StaticPriKey": c.StaticPriKey,
	}
	//d, _ := json.Marshal(config)
	return config
}

var letters = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func randSeq(n int) string {
	b := make([]rune, n)
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := range b {
		b[i] = letters[r.Intn(62)]
	}
	return string(b)
}

// GenerateWAConfig 生成随机设备配置
func GenerateWAConfig(mcc, mnc, simMcc, simMnc string) *WAConfig {
	var err error
	config := &WAConfig{}
	// 先写默认值
	config.SimMnc = "001"
	config.SimMcc = "510"
	config.MCC = "510"
	config.MNC = "000"
	// 如果存在传参, 就写入传参
	if mcc != "" {
		config.MCC = mcc
	}
	if mnc != "" {
		config.MNC = mnc
	}
	if simMcc != "" {
		config.SimMcc = simMcc
	}
	if simMnc != "" {
		config.SimMnc = simMnc
	}

	config.FDid = guuid.New().String()

	exidData := []byte(strings.ReplaceAll(guuid.New().String(), "-", "")[:16])
	config.Exid = base64.StdEncoding.EncodeToString(exidData)

	config.RegistrationId = keyhelper.GenerateRegistrationID()

	config.ClientStaticKeyPair, err = ecc2.GenerateKeyPair()
	if err != nil {
		fmt.Errorf(err.Error())
		return nil
	}
	config.IdentityKeyPair, err = keyhelper.GenerateIdentityKeyPair()
	if err != nil {
		fmt.Errorf(err.Error())
		return nil
	}

	config.SignedPreKey, err = keyhelper.GenerateSignedPreKey(config.IdentityKeyPair, 0, &serialize.JSONSignedPreKeyRecordSerializer{})
	if err != nil {
		fmt.Errorf(err.Error())
		return nil
	}
	idData := []byte(strings.ReplaceAll(guuid.New().String(), "-", "")[0:20])
	config.Id = base64.StdEncoding.EncodeToString(idData)
	tokenData := []byte(strings.ReplaceAll(guuid.New().String(), "-", "")[0:15])
	config.BackupToken = base64.StdEncoding.EncodeToString(tokenData)
	return config
}
